package cn.kgc.controller;

import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * @author wangyue
 * @version 1.0
 */
@RestController
@RequestMapping("/redisson")
@Api(tags = "redisson测试接口")
@Slf4j
public class RedissonController {
    @Resource
    private RedissonClient redissonClient;

    @GetMapping("/jian")
    public String  jian(){
        //获得名字叫做s1的信号量
        RSemaphore s1 = redissonClient.getSemaphore("goods-1");
//        try {
//            //从信号量中获得令牌,如果信号量中有令牌,程序接着向下执行。否则会一直等待,直到信号量中有令牌,才接着向下执行
//            //s1.acquire();
//        } catch (InterruptedException e) {
//            throw new RuntimeException(e);
//        }
            //尝试从信号量中获得令牌,如果信号量中有令牌,返回结果就是true。如果信号量中没有令牌,不会等待,直接返回false
           if(s1.tryAcquire()){
               System.out.println("用户秒杀到商品");
           }else{
               System.out.println("用户没有秒杀商品");
           }
        return s1.availablePermits()+"";
    }

    @GetMapping("/jia")
    public String getSemaphore(){
        //获得名字叫做s1的信号量
        RSemaphore s1 = redissonClient.getSemaphore("goods-1");
        //设置信号量中的令牌的初始数量10(只会在第一次访问时执行)
        s1.trySetPermits(10);
        //s1信号量中的令牌数+1
        //s1.release();
        //返回s1信号量中的令牌数
        return s1.availablePermits()+"";
    }

    @GetMapping("/readValue")
    public String readValue(){
        //获得读写锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("r-w-lock");
        RLock rLock = readWriteLock.readLock();
        //请求拿到读锁
        rLock.lock();
        log.info(Thread.currentThread().getName()+"获得了一把读锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            log.info(Thread.currentThread().getName()+"释放了读锁");
            rLock.unlock();
        }
        return "";
    }

    @GetMapping("/writeValue1")
    public String writeValue1(){
        //获得读写锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("r-w-lock");
        //创建一把写锁
        RLock writeLock = readWriteLock.writeLock();
        //请求写锁
        writeLock.lock();
        log.info(Thread.currentThread().getName()+"获得了一把写锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            log.info(Thread.currentThread().getName()+"释放了写锁");
            writeLock.unlock();
        }
        return "hello";
    }

    @GetMapping("/writeValue2")
    public String writeValue2(){
        //获得读写锁
        RReadWriteLock readWriteLock = redissonClient.getReadWriteLock("r-w-lock");
        //创建一把写锁
        RLock writeLock = readWriteLock.writeLock();
        //请求写锁
        writeLock.lock();
        log.info(Thread.currentThread().getName()+"获得了一把写锁");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            log.info(Thread.currentThread().getName()+"释放了写锁");
            writeLock.unlock();
        }
        return "hello";
    }


    @GetMapping("/hello")
    public String hello(){
        //1 创建分布式锁 (在Redis中创建了一个以mylock开头的key value是1)
        RLock rLock= redissonClient.getLock("mylock");
        //2 当前请求获得分布式锁,其他请求需要等待。等待当前请求释放锁以后,才能获得锁。
        rLock.lock();
        //使用lock方法时如果没有指定上锁的时间,默认时间是30s。如果30s之内还没有自己手动释放锁,Redisson自动续时。看门狗
        //使用lock方法时执行了上锁的时间,超过时间,Redisson自动释放锁。
        //所以在开发时如果指定了上锁的时间,被上锁的这一段业务功能一定要在指定的时间范围内执行完。在业务功能执行完手动释放锁。 释放自己线程的锁（X）
        //如果在开发时没有指定上锁的时间,那么在业务功能执行完以后一定要手动释放锁。(✔)
        log.info(Thread.currentThread().getName()+"获得了mylock锁");
        //3 请求等待5s以后才释放分布式锁
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }finally {
            log.info(Thread.currentThread().getName()+"释放了mylock锁");
            //使用unlock删除释放锁
            rLock.unlock();
        }
        //4 返回逻辑字符串
        return "hello";
    }
}
